package com.tbit.uqbike.webmanager.business.maintain_performance.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tbit.config.datasource.DataSource;
import com.tbit.uqbike.webmanager.business.maintain_performance.constant.PerformanceBizType;
import com.tbit.uqbike.webmanager.business.maintain_performance.constant.PerformanceRuleType;
import com.tbit.uqbike.webmanager.business.maintain_performance.dao.core.PerformanceRuleGroupDao;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.PerformanceRule;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.PerformanceRuleCondition;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.PerformanceRuleGroup;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author <a href="mailto:zheng.zebiao@tbit.com.cn">zb</a>
 * @since 2025/2/18
 */
@Slf4j
@Service
@AllArgsConstructor
public class PerformanceRuleGroupService extends ServiceImpl<PerformanceRuleGroupDao, PerformanceRuleGroup> {
    final PerformanceRuleService ruleService;
    final PerformanceRuleConditionService ruleConditionService;

    /**
     * 查询业务绩效配置
     */
    @DS(DataSource.CORE)
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public <T> T selectBizPerformanceConfig(Integer accountId, BiFunction<List<PerformanceRuleGroup>, Integer, T> converter, PerformanceBizType... bizTypes) {
        List<PerformanceRuleGroup> performanceRuleGroups = selectByAccountIdAndBizType(accountId, bizTypes);

        // 转换为业务对象
        return converter.apply(performanceRuleGroups, accountId);
    }

    /**
     * 查询绩效配置（原始DB对象）
     */
    public List<PerformanceRuleGroup> selectByAccountIdAndBizType(Integer accountId, PerformanceBizType... bizTypes) {
        QueryWrapper<PerformanceRuleGroup> groupQuery = Wrappers.query(PerformanceRuleGroup.class)
                .eq(PerformanceRuleGroup.Fields.accountId, accountId)
                .in(PerformanceRuleGroup.Fields.bizType, Arrays.asList(bizTypes));

        List<PerformanceRuleGroup> groups = this.list(groupQuery);
        if (CollUtil.isEmpty(groups)) {
            return Collections.emptyList();
        }
        Map<Long, PerformanceRuleGroup> groupIdMap = groups.stream()
                .collect(Collectors.toMap(PerformanceRuleGroup::getRuleGroupId, Function.identity()));

        // 根据规则组查询规则
        QueryWrapper<PerformanceRule> ruleQuery = Wrappers.query(PerformanceRule.class)
                .in(PerformanceRule.Fields.ruleGroupId, groups.stream()
                        .map(PerformanceRuleGroup::getRuleGroupId)
                        .collect(Collectors.toList())
                );
        List<PerformanceRule> rules = ruleService.list(ruleQuery);
        if (CollUtil.isEmpty(rules)) {
            return groups;
        }
        Map<Long, PerformanceRule> ruleIdMap = rules.stream()
                .collect(Collectors.toMap(PerformanceRule::getRuleId, Function.identity()));
        for (PerformanceRule rule : rules) {
            PerformanceRuleGroup group = groupIdMap.get(rule.getRuleGroupId());
            if (group != null) {
                if (group.getRules() == null) {
                    group.setRules(new ArrayList<>());
                }
                group.getRules().add(rule);
            }
        }

        // 根据规则查询条件
        QueryWrapper<PerformanceRuleCondition> conditionQuery = Wrappers.query(PerformanceRuleCondition.class)
                .in(PerformanceRuleCondition.Fields.ruleId, rules.stream()
                        .map(PerformanceRule::getRuleId)
                        .collect(Collectors.toList())
                );
        List<PerformanceRuleCondition> conditions = ruleConditionService.list(conditionQuery);
        for (PerformanceRuleCondition condition : conditions) {
            PerformanceRule rule = ruleIdMap.get(condition.getRuleId());
            if (rule != null) {
                if (rule.getConditions() == null) {
                    rule.setConditions(new ArrayList<>());
                }
                rule.getConditions().add(condition);
            }
        }
        return groups;
    }

    @Transactional
    public void saveRaw(Integer accountId, List<PerformanceRuleGroup> raw) {
        // 更新规则组，存在则更新，不存在则新增
        List<PerformanceRuleGroup> groupToAdd = new ArrayList<>();
        List<PerformanceRuleGroup> groupToUpdate = new ArrayList<>();

        Set<PerformanceBizType> bizToQuery = new HashSet<>();
        for (PerformanceRuleGroup group : raw) {
            bizToQuery.add(group.getBizType());
        }

        List<PerformanceRuleGroup> oldGroups = selectByAccountIdAndBizType(accountId,
                bizToQuery.toArray(new PerformanceBizType[0]));
        Map<PerformanceBizType, Map<PerformanceRuleType, PerformanceRuleGroup>> oldGroupMap = new HashMap<>();
        for (PerformanceRuleGroup group : oldGroups) {
            Map<PerformanceRuleType, PerformanceRuleGroup> groupMap = oldGroupMap.computeIfAbsent(group.getBizType(),
                    k -> new HashMap<>());
            groupMap.put(group.getRuleType(), group);
        }

        for (PerformanceRuleGroup newGroup : raw) {
            newGroup.setAccountId(accountId);

            if (!oldGroupMap.containsKey(newGroup.getBizType()) || !oldGroupMap.get(newGroup.getBizType()).containsKey(newGroup.getRuleType())) {
                newGroup.setCreateTime(LocalDateTime.now());
                newGroup.setUpdateTime(LocalDateTime.now());
                groupToAdd.add(newGroup);
            } else {
                PerformanceRuleGroup oldGroup = oldGroupMap.get(newGroup.getBizType()).get(newGroup.getRuleType());
                newGroup.setRuleGroupId(oldGroup.getRuleGroupId());
                newGroup.setCreateTime(oldGroup.getCreateTime());
                newGroup.setUpdateTime(LocalDateTime.now());
                groupToUpdate.add(newGroup);
            }
        }
        if (CollUtil.isNotEmpty(groupToAdd)) {
            this.saveBatch(groupToAdd);
        }
        if (CollUtil.isNotEmpty(groupToUpdate)) {
            this.updateBatchById(groupToUpdate);
        }

        // 删除规则组下规则
        List<Long> oldRuleIds = oldGroups.stream()
                .flatMap(group -> group.getRules() == null ? Stream.empty() : group.getRules().stream())
                .map(PerformanceRule::getRuleId)
                .collect(Collectors.toList());
        ruleService.removeByIds(oldRuleIds);

        // 删除规则下条件
        List<Long> oldConditionIds = oldGroups.stream()
                .flatMap(group -> group.getRules() == null ? Stream.empty() : group.getRules().stream())
                .flatMap(rule -> rule.getConditions() == null ? Stream.empty() : rule.getConditions().stream())
                .map(PerformanceRuleCondition::getConditionId)
                .collect(Collectors.toList());
        ruleConditionService.removeByIds(oldConditionIds);

        // 添加规则
        List<PerformanceRule> ruleToAdd = new ArrayList<>();
        for (PerformanceRuleGroup group : raw) {
            if (group.getRules() == null)
                continue;
            for (PerformanceRule rule : group.getRules()) {
                rule.setRuleGroupId(group.getRuleGroupId());
                rule.setCreateTime(LocalDateTime.now());
                ruleToAdd.add(rule);
            }
        }
        if (CollUtil.isNotEmpty(ruleToAdd)) {
            ruleService.saveBatch(ruleToAdd);
        }

        // 添加条件
        List<PerformanceRuleCondition> conditionToAdd = new ArrayList<>();
        for (PerformanceRule rule : ruleToAdd) {
            if (rule.getConditions() == null)
                continue;
            for (PerformanceRuleCondition condition : rule.getConditions()) {
                condition.setRuleId(rule.getRuleId());
                conditionToAdd.add(condition);
            }
        }
        if (CollUtil.isNotEmpty(conditionToAdd)) {
            ruleConditionService.saveBatch(conditionToAdd);
        }
    }
}
